package org.apache.cordova.appupdate;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Handler;
import android.widget.ProgressBar;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.LOG;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by LuoWen on 2015/10/27.
 * <p/>
 * Thanks @coolszy
 */
public class UpdateManager {
  public static final String TAG = "UpdateManager";

  /*
   * 远程的版本文件格式
   *   <update>
   *       <version>2222</version>
   *       <name>name</name>
   *       <url>http://192.168.3.102/android.apk</url>
   *   </update>
   */
  private String updateXmlUrl;
  private JSONObject options;
  private JSONArray args;
  private CordovaInterface cordova;
  private CallbackContext callbackContext;
  private String packageName;
  private Context mContext;
  private MsgBox msgBox;
  private Boolean isDownloading = false;
  private List<Version> queue = new ArrayList<>(1);
  private CheckUpdateThread checkUpdateThread;
  private DownloadApkThread downloadApkThread;

  public UpdateManager(Context context, CordovaInterface cordova) {
    this.cordova = cordova;
    this.mContext = context;
    packageName = mContext.getPackageName();
    msgBox = new MsgBox(mContext);
  }

  public UpdateManager(JSONArray args, CallbackContext callbackContext, Context context, JSONObject options) {
    this(args, callbackContext, context, "http://192.168.3.102:8080/update_apk/version.xml", options);
  }

  public UpdateManager(JSONArray args, CallbackContext callbackContext, Context context, String updateUrl, JSONObject options) {
    this.args = args;
    this.callbackContext = callbackContext;
    this.updateXmlUrl = updateUrl;
    this.options = options;
    this.mContext = context;
    packageName = mContext.getPackageName();
    msgBox = new MsgBox(mContext);
  }

  public UpdateManager options(JSONArray args, CallbackContext callbackContext)
    throws JSONException {
    this.args = args;
    this.callbackContext = callbackContext;
    this.updateXmlUrl = args.getString(0);
    this.options = args.getJSONObject(1);
    return this;
  }

  @SuppressLint("HandlerLeak")
  private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(android.os.Message msg) {
      super.handleMessage(msg);

      switch (msg.what) {
        case Constants.NETWORK_ERROR:
          //暂时隐藏错误
          //msgBox.showErrorDialog(errorDialogOnClick);
          callbackContext.error(Utils.makeJSON(Constants.NETWORK_ERROR, "network error"));
          break;
        case Constants.VERSION_COMPARE_START:
          compareVersions();
          break;
        case Constants.DOWNLOAD_CLICK_START:
          emitNoticeDialogOnClick();
          break;
        case Constants.DOWNLOAD_FINISH:
          isDownloading = false;
          break;
        case Constants.VERSION_UPDATING:
          callbackContext.success(Utils.makeJSON(Constants.VERSION_UPDATING, "success, version updating."));
          break;
        case Constants.VERSION_NEED_UPDATE:
          callbackContext.success(Utils.makeJSON(Constants.VERSION_NEED_UPDATE, "success, need date."));
          break;
        case Constants.VERSION_UP_TO_UPDATE:
          callbackContext.success(Utils.makeJSON(Constants.VERSION_UP_TO_UPDATE, "success, up to date."));
          break;
        case Constants.VERSION_COMPARE_FAIL:
          callbackContext.error(Utils.makeJSON(Constants.VERSION_COMPARE_FAIL, "version compare fail"));
          break;
        case Constants.VERSION_RESOLVE_FAIL:
          callbackContext.error(Utils.makeJSON(Constants.VERSION_RESOLVE_FAIL, "version resolve fail"));
          break;
        case Constants.REMOTE_FILE_NOT_FOUND:
          callbackContext.error(Utils.makeJSON(Constants.REMOTE_FILE_NOT_FOUND, "remote file not found"));
          break;
        default:
          callbackContext.error(Utils.makeJSON(Constants.UNKNOWN_ERROR, "unknown error"));
          break;
      }

    }
  };

  /**
   * 检测软件更新
   */
  public void checkUpdate() {
    LOG.d(TAG, "checkUpdate..");

    checkUpdateThread = new CheckUpdateThread(mContext, mHandler, queue, packageName, updateXmlUrl, options);
    this.cordova.getThreadPool().execute(checkUpdateThread);
    //new Thread(checkUpdateThread).start();
  }

  /**
   * Permissions denied
   */
  public void permissionDenied(String errMsg) {
    LOG.d(TAG, "permissionsDenied..");

    callbackContext.error(Utils.makeJSON(Constants.PERMISSION_DENIED, errMsg));
  }

  /**
   * 对比版本号
   */
  private void compareVersions() {
    Version version = queue.get(0);
    int versionCodeLocal = version.getLocalCode();
    int versionCodeRemote = version.getRemoteCode();

    boolean skipPromptDialog = false;
    try {
      skipPromptDialog = options.getBoolean("skipPromptDialog");
    } catch (JSONException ignored) {
    }

    boolean skipProgressDialog = false;
    try {
      skipProgressDialog = options.getBoolean("skipProgressDialog");
    } catch (JSONException ignored) {
    }

    //比对版本号
    //检查软件是否有更新版本
    if (versionCodeLocal < versionCodeRemote) {
      if (isDownloading) {
        msgBox.showDownloadDialog(null, null, null, !skipProgressDialog);
        mHandler.sendEmptyMessage(Constants.VERSION_UPDATING);
      } else {
        LOG.d(TAG, "need update");
        if (skipPromptDialog) {
          mHandler.sendEmptyMessage(Constants.DOWNLOAD_CLICK_START);
        } else {
          // 显示提示对话框,询问更新
          msgBox.showNoticeDialog(noticeDialogOnClick, version);
          mHandler.sendEmptyMessage(Constants.VERSION_NEED_UPDATE);
        }
      }
    } else {
      mHandler.sendEmptyMessage(Constants.VERSION_UP_TO_UPDATE);
      // Do not show Toast
      //Toast.makeText(mContext, getString("update_latest"), Toast.LENGTH_LONG).show();
    }
  }

  private UpdateDialog.OnCenterItemClickListener noticeDialogOnClick = (dialog, view) -> {
    dialog.dismiss();
    mHandler.sendEmptyMessage(Constants.DOWNLOAD_CLICK_START);
  };

  private void emitNoticeDialogOnClick() {
    isDownloading = true;

    boolean skipProgressDialog = false;
    try {
      skipProgressDialog = options.getBoolean("skipProgressDialog");
    } catch (JSONException e) {
    }

    // 显示下载对话框
    Map<String, Object> ret = msgBox.showDownloadDialog(
      downloadDialogOnClickNeg,
      downloadDialogOnClickPos,
      downloadDialogOnClickNeu,
      !skipProgressDialog);

    // 下载文件
    downloadApk((AlertDialog) ret.get("dialog"), (ProgressBar) ret.get("progress"));
  }

  /**
   * 手动安装
   * Download again
   */
  private OnClickListener downloadDialogOnClickNeu = new OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      //Implemented in DownloadHandler.java
    }
  };
  /**
   * 重新下载
   * Download again
   */
  private OnClickListener downloadDialogOnClickPos = new OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
      mHandler.sendEmptyMessage(Constants.DOWNLOAD_CLICK_START);
    }
  };
  /**
   * 转到后台更新
   * Update in background
   */
  private OnClickListener downloadDialogOnClickNeg = new OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
      // 设置取消状态
      //downloadApkThread.cancelBuildUpdate();
    }
  };

  private OnClickListener errorDialogOnClick = new OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
    }
  };

  /**
   * 下载apk文件
   *
   * @param mProgress
   * @param mDownloadDialog
   */
  private void downloadApk(AlertDialog mDownloadDialog, ProgressBar mProgress) {
    LOG.d(TAG, "downloadApk" + mProgress);

    // 启动新线程下载软件
    downloadApkThread = new DownloadApkThread(mContext, mHandler, mProgress, mDownloadDialog, checkUpdateThread.getMHashMap(), options);
    this.cordova.getThreadPool().execute(downloadApkThread);
    // new Thread(downloadApkThread).start();
  }

}
